import axios, { AxiosResponse } from 'axios';
//导入axios类型
import type { AxiosInstance, AxiosRequestConfig } from 'axios';
import type { LoadingInstance } from 'element-plus/lib/components/loading/src/loading';
import { ElLoading } from 'element-plus';

//定义接口；用于定义拦截器的类型和类型
interface RequestInterceptors<T = AxiosResponse> {
  //每个接口都是一个函数类型
  //请求
  requestInterceptor?: (config: AxiosRequestConfig) => AxiosRequestConfig;
  requestInterceptorCatch?: (error: any) => any;
  //响应
  // responseInterceptor?: (res: AxiosResponse) => AxiosResponse;
  responseInterceptor?: (res: T) => T;
  responseInterceptorCatch?: (error: any) => any;
}
//这里继承的原因是因为我们要对 requestConfig 在原有的AxiosRequestConfig
//之上扩展一个 我们写的RequestInterceptors接口 而已，
interface RequestConfig<T = AxiosResponse> extends AxiosRequestConfig {
  interceptors?: RequestInterceptors<T>;
  isShowLoading?: boolean;
}

class Request {
  //类中的属性
  instance: AxiosInstance;
  interceptors?: RequestInterceptors; //接收拦截器的设置
  loading?: LoadingInstance; //保存loading方法，用于关闭
  isShowLoading: boolean; //是否显示
  //构造方法
  constructor(config: RequestConfig) {
    //这里我们要改成 RequestConfig类型，这也是为什么我们要使用继承
    this.instance = axios.create(config);
    //ok，接下来就是使用拦截器了
    this.interceptors = config.interceptors;
    this.isShowLoading = config.isShowLoading ?? true;
    //从config种取出的拦截器是对应的实例的拦截器
    //请求
    this.instance.interceptors.request.use(
      this.interceptors?.requestInterceptor,
      this.interceptors?.requestInterceptorCatch
    );
    //响应
    this.instance.interceptors.response.use(
      this.interceptors?.responseInterceptor,
      this.interceptors?.responseInterceptorCatch
    );
    //添加所有实例都有的拦截器
    //全局请求
    this.instance.interceptors.request.use(
      (config) => {
        console.log('所有实例都有的拦截器');
        if (this.isShowLoading) {
          this.loading = ElLoading.service({
            //使用element的加载框
            //当数据加载成功后，通过this.loading.close关闭
            lock: true,
            text: '正在加载...',
            background: 'rgba(0,0,0,.5)'
          });
        }
        return config;
      },
      (error) => {
        return error;
      }
    );
    //全局响应
    this.instance.interceptors.response.use(
      (config) => {
        console.log('所有实例都有的拦截器');
        //响应成功后，关闭加载页
        this.loading?.close();
        return config;
      },
      (error) => {
        this.loading?.close();
        return error;
      }
    );
  }

  request<T>(config: RequestConfig<T>): Promise<T> {
    return new Promise((resolve, reject) => {
      //对单个请求config进行处理
      if (config.interceptors?.requestInterceptor) {
        config = config.interceptors.requestInterceptor(config);
      }
      //判断是否需要显示loading
      if (config.isShowLoading === false) {
        this.isShowLoading = config.isShowLoading;
      }
      this.instance
        .request<any, T>(config)
        .then((res) => {
          if (config.interceptors?.responseInterceptor) {
            res = config.interceptors.responseInterceptor(res);
          }
          resolve(res); //存放到成功方法的回调中
          this.isShowLoading = true;
        })
        .catch((error) => {
          this.isShowLoading = true;
          reject(error);
          return error;
        });
    });
  }
}

export default Request;
